package rebellion.util;

import java.util.Hashtable;

import ratkit.repast.RepastTestEnvironment;
import rebellion.Cop;
import rebellion.CoverageCounter;
import rebellion.Person;
import rebellion.fake.FakeCop;
import rebellion.fake.FakeCoverageCounter;
import repast.simphony.space.grid.Grid;

/**
 * This class provides the creation of elements of the Rebellion simulation
 * models in an essential manner.
 * 
 * @author İbrahim Çakırlar
 * @version 1.0
 */
public class RebellionEnvironment extends RepastTestEnvironment {

	/**
	 * Environment instance..
	 */
	private static RebellionEnvironment instance = null;

	/**
	 * List of existing agents in the environment.
	 */
	private Hashtable<String, Object> agents;

	/**
	 * List of died agents from the environment.
	 */
	private Hashtable<String, Object> diedAgents;

	/**
	 * Creates a new environment for the simulation model...
	 */
	private RebellionEnvironment() {
		super("Rebellion Test Agent Factory");
		// initialize agent lists..
		this.setAgents(new Hashtable<String, Object>());
		this.setDiedAgents(new Hashtable<String, Object>());
	}

	/**
	 * Returns the singleton instance of the simulation environment.
	 * 
	 * @return instance of the environment.
	 */
	public static RebellionEnvironment getInstance() {
		if (instance == null) {
			instance = new RebellionEnvironment();
		}
		return instance;
	}

	/**
	 * Creates a new {@code Person} instance for test.
	 * 
	 * @param agentName
	 *            name of the agent
	 * @param grid
	 *            grid of the agent in the test context.
	 * @param visNeighbors
	 *            visibility level of the agent.
	 * @param maxJailTerm
	 *            max jail value for the person.
	 * @param govLegitimacy
	 *            government legitimacy.
	 * @return created test agent instance.
	 */
	public Person createPerson(String agentName, Grid<Object> grid,
			int visNeighbors, int maxJailTerm, double govLegitimacy) {
		// create Person agent...
		Person testAgent = new Person(grid, visNeighbors, maxJailTerm,
				govLegitimacy);
		getAgents().put(agentName, testAgent);
		return testAgent;
	}

	/**
	 * Creates a new {@code CoverageCounter} agent for test.
	 * 
	 * @param agentName
	 *            name of the test agent created.
	 * @return {@link CoverageCounter} agent instance.
	 */
	public CoverageCounter createCovarageCounter(String agentName) {
		CoverageCounter counterAgent = new CoverageCounter();
		getAgents().put(agentName, counterAgent);
		return counterAgent;
	}

	/**
	 * Creates a new {@code FakeCoverageCounter} agent for test.
	 * 
	 * @param agentName
	 *            name of the test agent created.
	 * @return {@link FakeCoverageCounter1} agent instance.
	 */
	public FakeCoverageCounter createFakeCovarageCounter(String agentName) {
		FakeCoverageCounter counterAgent = new FakeCoverageCounter();
		getAgents().put(agentName, counterAgent);
		return counterAgent;
	}

	/**
	 * Creates a new {@code Cop} instance for test with given name.
	 * 
	 * @param agentName
	 *            name of the agent
	 * @param grid
	 *            grid of the test agent.
	 * @param visNeighbors
	 *            Neighbor visibility of the test agent.
	 * @return created wolf instance.
	 */
	public Cop createCop(String agentName, Grid<Object> grid, int visNeighbors) {
		// create Cop agent...
		Cop testAgent = new Cop(grid, visNeighbors);
		getAgents().put(agentName, testAgent);
		return testAgent;
	}

	/**
	 * Creates a new {@code FakeCop} instance for test with given name and
	 * parameters.
	 * 
	 * @param agentName
	 *            name of the agent
	 * @param grid
	 *            grid of the test agent.
	 * @param visNeighbors
	 *            neighbor visibility of the test agent.
	 * @return created wolf instance.
	 */
	public FakeCop createFakeCop(String agentName, Grid<Object> grid,
			int visNeighbors) {
		// create Cop agent...
		FakeCop testAgent = new FakeCop(grid, visNeighbors);
		getAgents().put(agentName, testAgent);
		return testAgent;
	}

	/**
	 * Resets the environment memory.
	 */
	public void reset() {
		this.setAgents(new Hashtable<String, Object>());
		this.setDiedAgents(new Hashtable<String, Object>());
	}

	/**
	 * @param agents
	 *            list of agents to set to the test environment.
	 */
	public void setAgents(Hashtable<String, Object> agents) {
		this.agents = agents;
	}

	/**
	 * @return a list of live agent in the environment.
	 */
	public Hashtable<String, Object> getAgents() {
		return agents;
	}

	/**
	 * @param diedAgents
	 *            list of dies agents to set.
	 */
	public void setDiedAgents(Hashtable<String, Object> diedAgents) {
		this.diedAgents = diedAgents;
	}

	/**
	 * @return a list of dies agents in the test environment.
	 */
	public Hashtable<String, Object> getDiedAgents() {
		return diedAgents;
	}

	/**
	 * Returns the created agent instance with given agent name...
	 * 
	 * @param key
	 *            name of the created agent.
	 * @return live agent instance.
	 */
	public Object getAgent(String key) {
		return getAgents().get(key);
	}

}
